'''
Created on Jul 17, 2009

@author: Roni
'''
import unittest
import os
import unittest
import cliques.mdp
import cProfile
import pstats
import graph
from cliques.cliqueFinder import cliqueFinder
from cliques.mdp.mdpBasedSearch import mdpBasedSearch
from cliques.mdp.heuristicMdp import heuristicMdp
import cliques.experiment_runner
import cliques.utils


class unittest_mdpLookahead(unittest.TestCase):

    def simulate_run(self, test_graph, algorithms, comp_funcs, k, start_node):
        ''' Use the algorithms to search for a k-clique on the test graph 
        starting from start_node, and compare them with comp_funcs '''        
        for algo in algorithms:
            algo.setup(test_graph, k, start_node)
        try:
            base_alg = algorithms[0]
            while base_alg.halt() == False:
                for alg in algorithms:
                    print "Step %d alg=%s" % (alg.iteration,alg)
                    alg.step()
                
                for compared_algo in algorithms[1:]:
                    for comp_func in comp_funcs:
                        current_func = comp_func
                        current_func(base_alg, compared_algo)
        except AssertionError, error:
            cliques.utils.export_graph(test_graph, "BUG-GRAPH[%d,%s].graph" % (k, start_node))
            print "Assertion of %s Failed" % current_func
            raise error
     
    def assert_halt(self,alg1,alg2):
        assert alg1.halt()==alg2.halt()
        
    def assert_current_node(self,alg1,alg2):
        assert alg1.current_node==alg2.current_node

    def assert_less_states(self,alg1,alg2):
        if "state_graph" in dir(alg1.solver):
            saving = len(alg1.solver.state_graph.nodes())-len(alg2.solver.state_graph.nodes())
            print "Saved %d" % saving
            assert saving>=0

    def clique_search_run_comparator(self,nodes,min_k,max_k,algorithms,comp_funcs):
        for edges in xrange(nodes+1,nodes+2):#xrange(nodes+1,nodes*(nodes-1)/2,1):
            print "--- Generating graph[%d,%d] --- " % (nodes,edges)
            test_graph = graph.graph()
            test_graph.generate(nodes,edges)
            self.compare(test_graph,min_k,max_k,algorithms,comp_funcs)
            
    def compare(self,test_graph,min_k,max_k,algorithms,comp_funcs):  
        ''' Compare the run of the algorithms using the comp_functions,
        when searching for k-cliques in the given graph '''   
        clique_finder = cliqueFinder()
        for k in xrange(min_k,min(max_k,len(test_graph.nodes()))):    
            clique_finder.setup(test_graph)
            #print "-- Searching for a %d-clique in test graph..." % k
            clique = clique_finder.find_clique(k,test_graph.nodes())
            if clique is not None:
                clique = set(clique)
               
            start_node = cliques.experiment_runner.choose_start(test_graph)
            self.simulate_run(test_graph, algorithms, comp_funcs, k, start_node)


    def testLookaheadLevels(self):
        ''' Verify that unlimited lookahead is equal to heuristic MDP '''
        unlimitedSolver = mdpBasedSearch(cliques.mdp.heuristicMdp.heuristicMdp,"Unlimited")
        very_large_solver = mdpBasedSearch(cliques.mdp.mdpLookahead.mdpLookahead,"lookahead",100)
        algorithms = [unlimitedSolver, very_large_solver]
        assertion_funcs = [self.assert_halt,self.assert_current_node, self.assert_less_states]
        max_iterations = 25
        for nodes in xrange(5,7):
            for iteration in xrange(max_iterations):
                print " ---- Nodes %d, Iteration %d/%d" % (nodes,iteration,max_iterations)
                self.clique_search_run_comparator(nodes, 3, 7, algorithms, assertion_funcs)        

    def clique_search_run_comparator(self,nodes,min_k,max_k,algorithms,comp_funcs):
        for edges in xrange(nodes+1,nodes+2):#xrange(nodes+1,nodes*(nodes-1)/2,1):
            print "--- Generating graph[%d,%d] --- " % (nodes,edges)
            test_graph = graph.graph()
            test_graph.generate(nodes,edges)
            self.compare(test_graph,min_k,max_k,algorithms,comp_funcs)


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testMdpNextStates']
#    cProfile.run("unittest.main()","mdp-test2.profile")    
#    profile_stats = pstats.Stats("mdp-test2.profile")
#    profile_stats.strip_dirs()
#    profile_stats.sort_stats('time')
#    profile_stats.print_stats(15)
    #import sys;sys.argv = ['', 'unittest_mdp.testHeuristicBug']
    unittest.main()
    
    
    